import os
import sys
import redis
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont, QIcon
from PyQt5.QtNetwork import QPasswordDigestor
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QSplitter,
    QWidget, QLabel, QLineEdit, QPushButton, QListWidget, QTextEdit, QMessageBox, QInputDialog
)
from redis.commands.search.reducers import count


class RedisManager(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Redis管理器")
        self.setGeometry(100, 100, 1100, 600)
        icon_path = os.path.join(os.path.dirname(__file__), 'img', 'redis.png')
        self.setWindowIcon(QIcon(icon_path))  # 添加窗口图标（需要一个 icon.png 文件）
        self.redis_client = None

        vbox = QVBoxLayout()
        hbox = QHBoxLayout()
        # 创建一个水平分割器
        splitter = QSplitter(Qt.Horizontal)

        # Connection Widgets
        self.host_input = QLineEdit(self)
        self.host_input.setPlaceholderText("地址 (例如, 127.0.0.1)")
        self.host_input.setText("10.2.170.236")
        self.host_input.setFont(QFont("楷体", 9))

        self.port_input = QLineEdit(self)
        self.port_input.setPlaceholderText("端口 (例如, 6379)")
        self.port_input.setText("6379")
        self.port_input.setFont(QFont("楷体", 9))

        self.password_input = QLineEdit(self)
        self.password_input.setEchoMode(QLineEdit.Password)
        self.password_input.setPlaceholderText("密码 (例如, 123456)")
        self.password_input.setText("s#a8*2#nlj")
        self.password_input.setFont(QFont("楷体", 9))

        self.connect_button = QPushButton("点击连接", self)
        self.connect_button.setFont(QFont("宋体", 20))
        self.connect_button.setStyleSheet("background-color: #4CAF50; color: white; padding: 5px; border-radius: 5px;")
        self.connect_button.clicked.connect(self.connect_to_redis)

        self.conn_status_label = QLabel("Redis未连接", self)
        self.conn_status_label.setFixedSize(100, 30)
        self.conn_status_label.setFont(QFont("宋体", 20))
        self.conn_status_label.setStyleSheet("background-color: #cfd9a6; color: red; padding: 5px; border-radius: 5px;")

        # 将组件加入水平布局
        hbox.addWidget(QLabel("Redis地址:", self))
        hbox.addWidget(self.host_input)
        hbox.addWidget(QLabel("端口:", self))
        hbox.addWidget(self.port_input)
        hbox.addWidget(QLabel("密码:", self))
        hbox.addWidget(self.password_input)
        hbox.addWidget(self.connect_button)
        hbox.addWidget(self.conn_status_label)

        # 创建展示key的组件
        self.keys_list = QListWidget(self)
        self.keys_list.setFont(QFont("Arial", 11))
        self.keys_list.setStyleSheet("border: 1px solid #ddd; padding: 5px;")
        self.keys_list.itemClicked.connect(self.load_value)
        # 创建key搜索框
        self.keys_search_input = QLineEdit()
        self.keys_search_input.setPlaceholderText("检索key")
        self.keys_search_input.setFont(QFont("楷体", 9))
        # 创建key搜索按钮
        self.keys_search_button = QPushButton("搜索", self)
        self.keys_search_button.setFont(QFont("宋体", 20))
        self.keys_search_button.clicked.connect(self.search_keys)
        # 创建刷新按钮
        self.keys_reflush_button = QPushButton("刷新", self)
        self.keys_reflush_button.setFont(QFont("宋体", 20))
        self.keys_reflush_button.clicked.connect(self.refresh_keys)
        # 创建监控按钮
        self.keys_minitor_button = QPushButton("监控", self)
        self.keys_minitor_button.setFont(QFont("宋体", 20))
        self.keys_minitor_button.clicked.connect(self.minitor_keys)

        # 创建左容器
        left_widget = QWidget()
        left_v_layout = QVBoxLayout()
        left_h_layout = QHBoxLayout()
        left_h_layout.addWidget(QLabel("Keys", self))
        left_h_layout.addWidget(self.keys_search_input)
        left_h_layout.addWidget(self.keys_search_button)
        left_h_layout.addWidget(self.keys_reflush_button)
        left_h_layout.addWidget(self.keys_minitor_button)
        left_v_layout.addLayout(left_h_layout)
        left_v_layout.addWidget(self.keys_list)
        left_widget.setLayout(left_v_layout)

        self.value_display = QTextEdit(self)
        self.value_display.setFont(QFont("Courier", 9))
        self.value_display.setStyleSheet("border: 1px solid #ddd; padding: 5px; background-color: #f9f9f9;")
        self.value_display.setReadOnly(True)
        # 创建容器
        right_widget = QWidget()
        right_layout = QVBoxLayout()
        right_layout.addWidget(QLabel("Value", self))
        right_layout.addWidget(self.value_display)

        # 按钮垂直布局
        button_layout = QVBoxLayout()
        self.add_key_button = QPushButton("ADD Key", self)
        self.add_key_button.setStyleSheet("background-color: #2196F3; color: white; padding: 5px; border-radius: 5px;")
        self.add_key_button.clicked.connect(self.add_key)
        self.delete_key_button = QPushButton("DEL Key", self)
        self.delete_key_button.setStyleSheet(
            "background-color: #f44336; color: white; padding: 5px; border-radius: 5px;")
        self.delete_key_button.clicked.connect(self.delete_key)
        # 把按钮加入按钮布局
        button_layout.addWidget(self.add_key_button)
        button_layout.addWidget(self.delete_key_button)
        button_layout.addStretch()
        # 把按钮布局加入右布局
        right_layout.addLayout(button_layout)
        # 把右布局加到右容器
        right_widget.setLayout(right_layout)

        # 用水平分割器加入左右容器
        splitter.addWidget(left_widget)
        splitter.addWidget(right_widget)

        # 把水平布局加入大垂直布局
        vbox.addLayout(hbox)
        # 大垂直布局添加分割器
        vbox.addWidget(splitter)

        # 总结：
        # 布局加入布局用addLayout，
        # 布局加入容器用setLayout

        container = QWidget()
        container.setLayout(vbox)
        self.setCentralWidget(container)

        # Styling the main window
        self.setStyleSheet("""
            QMainWindow {
                background-color: #f0f0f0;
            }
            QLabel {
                font-size: 14px;
                font-weight: bold;
            }
            QPushButton {
                font-size: 12px;
                font-weight: bold;
            }
        """)

    def connect_to_redis(self):
        host = self.host_input.text()
        port = self.port_input.text()
        pwd = self.password_input.text()

        try:
            self.redis_client = redis.StrictRedis(host=host, port=int(port), password=pwd, decode_responses=False)
            self.redis_client.ping()
            QMessageBox.information(self, "Success", "Redis连接成功!")
            self.conn_status_label.setText("Redis已连接")
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Redis连接失败: {e}")

    def refresh_keys(self):
        if not self.redis_client:
            QMessageBox.warning(self, "警告", "Redis 客户端未连接")
            return
        try:
            self.keys_list.clear()
            # 初始化游标
            cursor = '0'
            while cursor != 0:
                # 执行SCAN命令，每次返回1000个键
                cursor, keys = self.redis_client.scan(cursor=cursor, match="AMP:*", count=1000)
                for key in keys:
                    self.keys_list.addItem(key.decode('utf-8'))
        except Exception as e:
            QMessageBox.critical(self, "Error", f"键加载失败: {e}")

    def search_keys(self):
        if not self.redis_client:
            QMessageBox.warning(self, "警告", "Redis 客户端未连接")
            return
        key = self.keys_search_input.text()
        if not key:
            QMessageBox.critical(self, "警告", "不允许空值")
        try:
            self.keys_list.clear()
            self.keys_list.addItem(key)
        except Exception as e:
            QMessageBox.critical(self, "Error", f"搜索失败:{e}")

    def minitor_keys(self):
        if not self.redis_client:
            QMessageBox.warning(self, "警告", "Redis 客户端未连接")
            return
        try:
            info = self.redis_client.info()
            self.value_display.clear()
            # 筛选需要显示的关键指标
            key_metrics = {
                "redis_version": "Redis 版本",
                "used_memory_human": "内存使用量",
                "used_memory_peak_human": "内存历史最大使用量",
                "used_memory_rss_human": "内存实际分配量",
                "blocked_clients": "当前阻塞连接数",
                "connected_clients": "当前客户端连接数",
                "db0.keys": "每个数据库中的键数量",
                "expires": "设置过期时间键数量",
                "total_commands_processed": "命令处理总数",
                "total_connections_received": "连接总数",
                "instantaneous_ops_per_sec": "每秒操作数",
                "uptime_in_days": "运行天数",
            }
            display_data = ""
            for key, label in key_metrics.items():
                if key in info:
                    display_data += f"{label}: {info[key]}\n"

            self.value_display.setText(display_data)
        except Exception as e:
            QMessageBox.critical(self, "错误", f"获取监控信息失败:\n{str(e)}")

    def load_value(self, item):
        if not self.redis_client:
            QMessageBox.warning(self, "警告", "Redis 客户端未连接")
            return
        while True:
            try:
                key = item.text()
                # 判断key类型
                key_type = self.redis_client.type(key)
                if key_type == "string":
                    # 字符串类型
                    value = self.redis_client.get(key)
                elif key_type == "list":
                    # 列表类型
                    value = self.redis_client.lrange(key, 0, -1)
                elif key_type == "set":
                    # 集合类型
                    value = self.redis_client.smembers(key)
                elif key_type == 'zset':
                    # 有序集合类型
                    value = self.redis_client.zrange(key, 0, -1, withscores=True)
                elif key_type == 'hash':
                    # 哈希类型
                    value = self.redis_client.hgetall(key)
                else:
                    value = "Not Support"
                print(key_type)
                self.value_display.setText(f"类型: {key_type}\n值: {value if value else '(empty value)'}")
            except redis.exceptions.ResponseError as e:
                if "MOVED" in str(e):
                    #获取新的节点地址
                    new_slot_info = e.args[1].decode('utf-8')
                    new_node = new_slot_info.split(' ')[1]
                    redis_url = redis_url.replace(self.host_input.text(), new_node)
                    print(redis_url)
                    continue
            except Exception as e:
                QMessageBox.critical(self, "Error", f"值加载失败: {e}")

    def add_key(self):
        if not self.redis_client:
            QMessageBox.warning(self, "警告", "Redis 客户端未连接")
            return
        key, ok1 = QInputDialog.getText(self, "Add Key", "Enter key:")
        if not ok1 or not key.strip():
            return

        value, ok2 = QInputDialog.getText(self, "Add Key", "Enter value:")
        if not ok2:
            return

        try:
            self.redis_client.set(key, value)
            QMessageBox.information(self, "Success", f"Key '{key}' added.")
            self.refresh_keys()
        except Exception as e:
            QMessageBox.critical(self, "Error", f"Failed to add key: {e}")

    def delete_key(self):
        if not self.redis_client:
            QMessageBox.warning(self, "警告", "Redis 客户端未连接")
            return
        selected_items = self.keys_list.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "Warning", "请选中一个key删除")
            return

        key = selected_items[0].text()
        try:
            self.redis_client.delete(key)
            QMessageBox.information(self, "Success", f"已删除'{key}'")
            self.refresh_keys()
        except Exception as e:
            QMessageBox.critical(self, "Error", f"删除失败: {e}")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = RedisManager()
    window.show()
    sys.exit(app.exec_())
